package insight.google.game.era.bo;

//import insight.google.game.era.bo.Room;


import insight.google.game.era.bo.card.CharacterCard;


import insight.google.game.era.bo.card.GameCard;
import insight.google.game.era.bo.card.RoleCard;
import insight.google.game.era.client.proxy.PlayerClientProxyImpl;
import insight.google.game.era.client.proxy.RoomClientProxyImpl;
import insight.google.game.era.core.Util;
import insight.google.game.era.core.exception.InsightException;
import insight.google.game.era.core.hub.HubServiceManager;
import insight.google.game.era.core.hub.PendingEvents;
import insight.google.game.era.core.hub.UserEvents;
import insight.google.game.era.data.AppDataManagerFactory;
import insight.google.game.era.data.GameUserDataManager;
import insight.google.game.era.data.RoomDataManager;
import insight.google.game.era.data.User;
import insight.google.game.era.data.UserHistory;
import insight.google.game.era.data.AppDataManagerFactory.DataManager;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.jdo.annotations.FetchGroup;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.NullValue;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.annotations.DataTransferObject;
import org.directwebremoting.annotations.RemoteProperty;
import org.directwebremoting.proxy.ScriptProxy;


import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;


@DataTransferObject
@PersistenceCapable(identityType = IdentityType.APPLICATION,detachable="true")
public class GameUser {
	
	@Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
	@PrimaryKey
	protected Key id;
	
	@RemoteProperty
	@Persistent
	protected String name;
	
	@RemoteProperty
	@Persistent
	protected String email;
	
	@NotPersistent
	protected ScriptProxy scriptProxy;
	
	@Persistent(defaultFetchGroup="true")
	private GameRoom currentRoom;
	
	@RemoteProperty
	private RoleCard roleCard = null;

	@Persistent
	private String roleCardId = null;

	@RemoteProperty
	private CharacterCard characterCard = null;
	
	@Persistent
	private String characterCardId = null;
	
	@RemoteProperty
	@Persistent
	private int state = STATE_USER;
	
	@Persistent(nullValue=NullValue.NONE)
	private Key roomId;

	@RemoteProperty
	@Persistent
	private int blood = 4;
	
	@Persistent(nullValue=NullValue.NONE)
	private List<String> gameCardIdList;
	
	@RemoteProperty
	@Persistent
	private List<String> attackUserList = new ArrayList<String>();

	@RemoteProperty
	@Persistent
	private boolean registerAttack = false;
	
	@RemoteProperty
	@Persistent
	private int attackDistance = 1;

	@RemoteProperty
	@Persistent
	private int defendDistance = 0;
	
	@RemoteProperty
	@Persistent
	private boolean isActive = false;
	
	@Persistent
	private List<String> activeCards;
	
	@RemoteProperty
	@Persistent
	private boolean isOnTurn = false;

	@Persistent(mappedBy="pendingUser",defaultFetchGroup="true")
	List<PendingEvents> eventList = new ArrayList<PendingEvents>();
	
	@RemoteProperty
	@Persistent
	private boolean havePendingEvent = false;

	@RemoteProperty
	@Persistent
	private boolean isHanged = false;
	
	private GameUserDataManager dataManager;

	@Persistent(nullValue=NullValue.NONE)
	private List<Key> equipementCardIdList;
	
	private List<String> equipmentCards;
	
	@RemoteProperty
	@Persistent
	private String recievedPLayedCard;
	
	
	public static final int STATE_GUEST = -1;
	public static final int STATE_USER = 0;
	public static final int STATE_PLAYER = 1;
	public static final int STATE_DEAD = 2;
	public static final int STATE_DROP = 3;
	public static final int STATE_QUIT_B4_GAME_STARTED = 4;
	public static final int STATE_QUIT_AFTER_GAME_STARTED = 5;
	public static final int STATE_WINNER = 6;
	public static final int STATE_ON_TRUN = 7;
	public static final int STATE_DYING = 8;
	
	public GameUser(String name,String email) {
		this.name = name;
		this.email = email;
	}
	
	
	public void quitRoom() {
		if (currentRoom.getGameState() == Room.INITIALIZED || currentRoom.getGameState() == Room.READY_FOR_START) {
			this.state = STATE_USER;
		} else if (currentRoom.getGameState() == Room.STARTED) {
			this.state = STATE_QUIT_AFTER_GAME_STARTED;
		}

	}
	
	
	public void updateGameLog(List<GameActionLog> gameLogList) {
		if(this.scriptProxy != null){
			RoomClientProxyImpl.getInstance().updateGameLog(this.scriptProxy, getCurrentRoom().getJsComponentId(), gameLogList);
		}
				
	}
	

	public Key getId() {
		return id;
	}

	public void setId(Key id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public ScriptProxy getScriptProxy() {
		return scriptProxy;
	}

	public void setScriptProxy(ScriptProxy scriptProxy) {
		this.scriptProxy = scriptProxy;
	}

	public GameRoom getCurrentRoom() {
		return currentRoom;
	}

	public void setCurrentRoom(GameRoom currentRoom) {
		this.currentRoom = currentRoom;
	}


	public int getState() {
		return state;
	}


	public void setState(int state) {
		this.state = state;
	}


	public int getBlood() {
		return blood;
	}


	public void setBlood(int blood) {
		this.blood = blood;
	}
	
	public RoleCard getRoleCard() {
		if(this.roleCard == null && this.roleCardId != null){
			this.roleCard = RoleCard.getRoleCardById(this.roleCardId);
		}
		//modify end
		return this.roleCard;
	}
	
	
	
	
	public void syncRoleCard(RoleCard roleCard){
		this.roleCard = roleCard;
	}

	public void setRoleCard(RoleCard roleCard)throws InsightException {
		this.roleCardId = roleCard.getId();		//modify
		this.roleCard = roleCard;
		this.roleCard.setUser(this);
		//log.debug("ROLE CARD for user  ---  " + this.name +"  is ---  "+this.roleCard);
		if(this.scriptProxy!= null && currentRoom != null){
			PlayerClientProxyImpl.getInstance().dispatchRoleCard(
					this.scriptProxy, currentRoom.getJsComponentId(),
					this.roleCard, currentRoom.getDataVersion());
		}
	}

	public CharacterCard getCharacterCard() {
		if(this.characterCard == null && this.characterCardId != null){
			this.characterCard = CharacterCard.getCharactCardById(this.characterCardId);
		}
		return this.characterCard;
		//modify end
	}

	public void setCharacterCard(CharacterCard character) throws InsightException{
		this.characterCard = character;
		this.characterCardId = character.getId();
		this.characterCard.setUser(this);
		//log.debug("Character card for "+ this.name +"  is   "+ this.characterCard);
		if(this.scriptProxy!= null && currentRoom != null){
			PlayerClientProxyImpl.getInstance().dispatchCharacterCard(
					this.scriptProxy, currentRoom.getJsComponentId(),
					this.characterCard, currentRoom.getDataVersion());
		}
	}

	public void initUserForGame(ArrayList<GameCard> cards) {
		this.setGameCards(cards);
		this.calulateInitialBlood();
	}

	public List<String> getGameCardIdList() {
		return gameCardIdList;
	}

	public void setGameCards(ArrayList<GameCard> gameCards) {
		List<String> cardKeys = new ArrayList<String>();
		for (GameCard gameCard : gameCards) {
			cardKeys.add( gameCard.getId());
		}
		this.setGameCardIdList(cardKeys);
	}

	public void setGameCardIdList(List<String> gameCardIdList) {
		this.gameCardIdList = new ArrayList<String>(gameCardIdList);
	}

	private void calulateInitialBlood() {
		this.blood = 4;
	}

	public List<String> getAttackUserList() {
		return attackUserList;
	}

	public void setAttackUserList(List<String> attackUserList) {
		this.attackUserList = attackUserList;
	}

	public boolean getRegisterAttack() {
		return registerAttack;
	}

	public void setRegisterAttack(boolean registerAttack) {
		this.registerAttack = registerAttack;
	}
	
	
	
	public String getRecievedPLayedCard() {
		return recievedPLayedCard;
	}


	public void setRecievedPLayedCard(String recievedPLayedCard) {
		this.recievedPLayedCard = recievedPLayedCard;
	}


	@RemoteProperty
	public int getCardCount(){
		if(gameCardIdList != null){
			return gameCardIdList.size();
		}
		return 0;
	}

	@RemoteProperty
	public List<GameCard> getGameCards() {
		//return new ArrayList<GameCard>(gameCards.values());
		if(this.gameCardIdList == null || this.gameCardIdList.size()<=0) return null;
		List<GameCard> cardList = new ArrayList<GameCard>();
		for(String cardId : this.gameCardIdList){
			cardList.add(GameCard.getGameCardById(cardId));
		}
		return cardList;
	}
	
	public List<GameCard> getGameCards2(GameUserDataManager gameUserDataManager ) {
		//return new ArrayList<GameCard>(gameCards.values());
		if(this.gameCardIdList == null || this.gameCardIdList.size()<=0) return null;

		List<GameCard> cardList = new ArrayList<GameCard>();
		for(String cardId : this.gameCardIdList){
			cardList.add(GameCard.getGameCardById(cardId));
		}
		return cardList;
	}
	
	public void registerAttackableUser2(String jsComponentId, GameUserDataManager userDataManager){
		if(jsComponentId != null && this.getScriptProxy() != null){
			List<GameUser> attackableUsers = new ArrayList<GameUser>();
			for (String userName : attackUserList) {
				GameUser user = userDataManager.findByName(userName);
				if(user != null){
					attackableUsers.add(user);
				}
			}
			PlayerClientProxyImpl.getInstance().registerAttackableUser(this.getScriptProxy(), jsComponentId,attackableUsers);
			
		}
	}
	
	public int getAttackDistance() {
		return attackDistance;
	}

	public void setAttackDistance(int attackDistance) {
		this.attackDistance = attackDistance;
	}

	public int getDefendDistance() {
		return defendDistance;
	}

	public void setDefendDistance(int defendDistance) {
		this.defendDistance = defendDistance;
	}

	public void addGameCard(ArrayList<GameCard> card,String jsComponentId) {
		if (this.gameCardIdList == null)
			this.gameCardIdList = new ArrayList<String>();
		for (GameCard gameCard : card) {
			this.gameCardIdList.add(gameCard.getId());
		}
		if(jsComponentId != null){
			if(this.getScriptProxy() != null){
				PlayerClientProxyImpl.getInstance().recieveCard(this.getScriptProxy(), jsComponentId,card);
			}else{
			}
		}
	}
	
	public List<String> getActiveCards() {
		return activeCards;
	}

	public void setActiveCards(List<String> activeCards) {
		this.activeCards = activeCards;
		
	}
	public void setActiveCards(List<String> activeCards,String jsComponentId) {
		this.activeCards = activeCards;
		if(this.getScriptProxy() != null){
			PlayerClientProxyImpl.getInstance().setActiveCard(this.getScriptProxy(), jsComponentId,this.activeCards);
	 	}
	}
	
	public boolean isActive() {
		return isActive;
	}

	public boolean getIsActive() {
		return isActive;
	}

	public void setActive(boolean isActive) {
		this.isActive = isActive;
	}

	public void readyToPlay(String jsComponentId){
		this.isActive = true;
		if(this.getScriptProxy() != null){
			PlayerClientProxyImpl.getInstance().readyToPlay(this.getScriptProxy(), jsComponentId);
		}
	}

	public void setClientActive(boolean isActive, String jsComponentId) {
		this.isActive = isActive;
		 if(this.getScriptProxy() != null){
	 			PlayerClientProxyImpl.getInstance().setActive(this.getScriptProxy(), jsComponentId, isActive);
	 		}
	}
	
//	@RemoteProperty
	public int cardCount(){
		if(gameCardIdList != null){
			return gameCardIdList.size();
		}
		return 0;
	}

	public boolean isOnTurn() {
		return isOnTurn;
	}

	public boolean getIsOnTurn() {
		return isOnTurn;
	}

	public void setOnTurn(boolean isOnTurn) {
		this.isOnTurn = isOnTurn;
	}

	public GameCard findCardByGenratedId(String cardId) {
		//To Do
		GameUserDataManager userdataManager = (GameUserDataManager)AppDataManagerFactory.getInstance().getDataManager(DataManager.GAMEUSER_DATA_MANAGER.toString(),Util.createTranscationHandler());
		return userdataManager.findCardByGenratedId(cardId);
	}

	public GameCard findCardByGenratedId2(GameUserDataManager userdataManager, String cardId) {
		return GameCard.getGameCardById(cardId);
	}

	public void removeCard(String cardId) {
		if(gameCardIdList != null){
			
			for (Iterator iterator = this.gameCardIdList.iterator(); iterator.hasNext();) {
				String gameCardId = (String)iterator.next();
				if(cardId.equals(gameCardId)){
					iterator.remove();
				}
			}
		}
	}
	
	public GameUserDataManager getDataManager() {
		return dataManager;
	}

	public void setDataManager(GameUserDataManager dataManager) {
		this.dataManager = dataManager;
	}

	public void addBlood(int blood) {
		this.blood += blood;
		//addBlood(blood,null);
		
	}
	public void addBlood(int blood,String jsComponentId) {
//		if(blood>0) this.blood += blood;
		
		if(jsComponentId != null){
			if(this.getScriptProxy() != null){
				PlayerClientProxyImpl.getInstance().healLife(this.getScriptProxy(), jsComponentId,blood);
			}
		}
	}
	
	public void removeBlood(int noOfBlood) {
		try{
			this.blood -= noOfBlood;
			if (this.blood <= 0) {
				this.state = STATE_DEAD;
				RoomDataManager roomDataManager = new RoomDataManager(Util.createTranscationHandler());
//				GameRoom currentRoom = roomDataManager.findById(this.roomId);
//				currentRoom.notifyUserQuit(this);
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	public void setRoomId(Key roomId) {
		this.roomId = roomId;
		
	}

	public boolean removeBloodAndCheckDead(int noOfBlood, String jsComponentId) {
		this.blood -= noOfBlood;
//		this.blood=0;
		if (this.blood <= 0) {
			if(jsComponentId != null){
				if(this.getScriptProxy() != null){
			        List<String> activeCards = new ArrayList<String>();
			        activeCards.add("milk");
			        this.setActiveCards(activeCards,jsComponentId);

			        PlayerClientProxyImpl.getInstance().askSaveSelfExec(this.getScriptProxy(), jsComponentId);
			        
			        //set user state is dying
					this.state = STATE_DYING;
			        return true;
				}
			}
		}
		return false;
	}
	
	public void dead(GameRoom currentRoom){
		try{
			this.state = STATE_DEAD;
			currentRoom.notifyUserQuit(this);
		}catch(Exception e){
			e.printStackTrace();
		}
	}

	public List<PendingEvents> getEventList() {
		return eventList;
	}
	public void setEventList(List<PendingEvents> eventList) {
		this.eventList = eventList;
	}
	
	public void addPendingEvent(PendingEvents event){
		this.eventList.add(event);
	}
	
	public synchronized boolean  processPendingEvents(List<PendingEvents> events){
		if(events == null || events.size() <= 0) return true;
		for (PendingEvents pendingEvent : events) {
			pendingEvent.processPendingEvents(this);
//			eventList.remove(pendingEvent);
		}
		//eventList = new ArrayList<PendingEvents>();
		
		return true;
	}


	public boolean getIsHanged() {
		return isHanged;
	}

	public void setHanged(boolean isHanged) {
		this.isHanged = isHanged;
	}

	public boolean getHavePendingEvent() {
		return havePendingEvent;
	}

	public void setHavePendingEvent(boolean havePendingEvent) {
		this.havePendingEvent = havePendingEvent;
	}

	public void addActiveCard(String activeCard) {
		this.activeCards.add(activeCard);
	}

	public void removeActiveCard(String activeCard) {
		this.activeCards.remove(activeCard);
	}

	public void addGameCard(GameCard card) {
		if (gameCardIdList == null)
			gameCardIdList = new ArrayList<String>();
		synchronized (gameCardIdList) {
			//gameCards.put(card.getId(), card);
			//gameCardIdList.add(KeyFactory.keyToString(card.getId()));
			gameCardIdList.add(card.getId());
			RoomDataManager roomDataManager = (RoomDataManager) AppDataManagerFactory.getInstance().getDataManager(DataManager.ROOM_DATA_MANAGER.toString(),Util.createTranscationHandler());
			GameRoom currentRoom = roomDataManager.findById(this.roomId);
			//currentRoom.notifyUsersCardCount(this);
		}
		
		
	}
	
	public void addGameCard(String cardId) {
		if (this.gameCardIdList == null)
			this.gameCardIdList = new ArrayList<String>();
		synchronized (this.gameCardIdList) {
			//gameCards.put(card.getId(), card);
			//gameCardIdList.add(KeyFactory.keyToString(card.getId()));
			this.gameCardIdList.add(cardId);
			RoomDataManager roomDataManager = (RoomDataManager) AppDataManagerFactory.getInstance().getDataManager(DataManager.ROOM_DATA_MANAGER.toString(),Util.createTranscationHandler());
			GameRoom currentRoom = roomDataManager.findById(this.roomId);
			//currentRoom.notifyUsersCardCount(this);
		}
	}
	
	public void dualCardPolicyExecute(String orgCard,String jsComponentId,String matchMethod,String senderName){
		if(jsComponentId != null){
			if(this.getScriptProxy() != null){
				PlayerClientProxyImpl.getInstance().duelCardPolicyExe(this.getScriptProxy(), jsComponentId,orgCard,matchMethod,senderName);
			}else{
				//pending
				HashMap<String, String> data = new HashMap<String, String>();
				data.put("card", orgCard);
				data.put("methodName", matchMethod);
				data.put("senderName", senderName);
				
				HubServiceManager.getInstance().addPendingEvent(this,
																	jsComponentId,
																	data, 
																	UserEvents.PLAYERPROXY_DUALCARD_POLICYEXECUTE.toString()
																	);
			}
		}
	}
	
	public void jingLangCardExecute(String orgCard,String jsComponentId,String matchMethod,String senderName){
		if(orgCard.equals("")){
			this.dualCardPolicyExecute(orgCard, jsComponentId, matchMethod, senderName);
		}
	}
	
	public void enablePolicyExecute(String jsComponentId){
		if(this.getScriptProxy() != null){
			PlayerClientProxyImpl.getInstance().enablePolicyExec(this.getScriptProxy(), jsComponentId,this);
	 	}else{
	 	//pending
	 	HubServiceManager.getInstance().addPendingEvent(this,
						jsComponentId,
						this, 
						UserEvents.PLAYERPROXY_ENABLE_POLICYEXECUTE.toString()
				);
	 	}
	}
	
	public void removeClientSelectedCards(String jsComponentId){
		 if(jsComponentId != null){
				if(this.getScriptProxy() != null){
					PlayerClientProxyImpl.getInstance().removeClientSelectedCard(this.getScriptProxy(), jsComponentId);
				}else{
					//pending
					PendingEvents pendingEvent = new PendingEvents();
					pendingEvent.setData(null);
					pendingEvent
							.setFunctionName(UserEvents.PLAYERPROXY_REMOVE_CLIENT_SELECTEDCARD
									.toString());
					pendingEvent.setJsComponentId(jsComponentId);
					HubServiceManager.getInstance().addPendingEvent(this, pendingEvent);
				}
			}
	}

	@RemoteProperty
	public List<GameCard> getEquipmentCards() {
		List<GameCard> cardList = new ArrayList<GameCard>();
		if(this.equipmentCards != null){
			for(String cardId : this.equipmentCards){
				cardList.add(GameCard.getGameCardById(cardId));
			}
		}
		return cardList;
	}

	public void setEquipmentCards(ArrayList<String> equipmentCards) {
		this.equipmentCards = equipmentCards;
	}

	public void addEquipmentCards(GameCard card) {
		if (this.equipmentCards == null)
			this.equipmentCards = new ArrayList<String>();
		synchronized (this.equipmentCards) {
			equipmentCards.add(card.getId());
//			// notify equipement crad
//			this.currentRoom.notifyUsersEquipementCard(this);
		}
	}

	public void addEquipmentCards(String cardId) {
		if (this.equipmentCards == null)
			this.equipmentCards = new ArrayList<String>();
		synchronized (this.equipmentCards) {
			equipmentCards.add(cardId);
//			// notify equipement crad
//			this.currentRoom.notifyUsersEquipementCard(this);
		}
	}
	
	public void removeEquipmentCards(String cardId) {
	}

	public boolean checkSameTypeEquipment(GameCard card) {
		//To Do
		List<GameCard> equipmentCards = this.getEquipmentCards();
		for(GameCard equipment : equipmentCards){
			if( equipment.getName().equals(card.getName()) ){
				return true;
			}
		}
		return false;
	}

	public void registerAttackableUser(String jsComponentId){
		if(jsComponentId != null && this.getScriptProxy() != null){
			List<GameUser> attackableUsers = new ArrayList<GameUser>();
			GameUserDataManager userDataManager = (GameUserDataManager) AppDataManagerFactory.getInstance().getDataManager(DataManager.GAMEUSER_DATA_MANAGER.toString(),Util.createTranscationHandler());
			for (String userName : attackUserList) {
				GameUser user = userDataManager.findByName(userName);
				if(user != null){
					attackableUsers.add(user);
				}
			}
			PlayerClientProxyImpl.getInstance().registerAttackableUser(this.getScriptProxy(), jsComponentId,attackableUsers);
			
		}
	}
	
	public void replaceEquipmentCard(GameCard card,String jsComponentId){
		GameCard equipmentCard = null;
		for (Iterator iterator = this.equipmentCards.iterator(); iterator.hasNext();) {
			String gameCardId = (String)iterator.next();
			equipmentCard = GameCard.getGameCardById(gameCardId);
			if(card.getName().equals(equipmentCard.getName())){
				iterator.remove();
			}
		}
		this.addEquipmentCards(card);
	}
	
	public void refreshEquipmentCard(String jsComponentId){
		if(jsComponentId != null){
			if(this.getScriptProxy() != null){
				PlayerClientProxyImpl.getInstance().refreshEquipmentCard(this.getScriptProxy(), jsComponentId,this.getEquipmentCards());
			}
		}
	}
	
}
